#include "application.h"
#include <cstring>
#include <esp_log.h>
#include <cJSON.h>
#include <driver/gpio.h>
#include <arpa/inet.h>
#include <esp_event.h>
#include <web_socket.h>
#include "boards/board.h"
#include "boards/system_info.h"
#include "boards/websocket_protocol.h"
#include "base64_client.h"
#include "config.h"


#define TAG "Application"
// 语音状态str
static const char* const STATE_STRINGS[] = {
    "unknown",
    "starting",
    "configuring",
    "idle",
    "connecting",
    "listening",
    "speaking",
    "upgrading",
    "fatal_error",
    "invalid_state"
};

Application::Application() {
    // 创建事件组句柄
    event_group_ = xEventGroupCreate();
    // 创建后台任务调度器
    background_task_ = new BackgroundTask(4096 * 8);
    // 创建socket对象
    socket_protocol_ = new WebsocketProtocol();
}


Application::~Application() {
    // 删除后台任务调度器
    if (background_task_ != nullptr) {
        delete background_task_;
    }
    // 删除事件组句柄
    vEventGroupDelete(event_group_);
    //断开连接并删除
    socket_protocol_->CloseAudioChannel();
}

void Application::Schedule(std::function<void()> callback) {
    std::lock_guard<std::mutex> lock(mutex_);
    main_tasks_.push_back(std::move(callback));
    xEventGroupSetBits(event_group_, SCHEDULE_EVENT);
}

void Application::SetDeviceState(DeviceState state) {
    if (device_state_ == state) {
        return;
    }
    device_state_ = state;
    ESP_LOGI(TAG, "STATE: %s", STATE_STRINGS[device_state_]);

    // The state is changed, wait for all background tasks to finish
    background_task_->WaitForCompletion();

    // The state is changed, control led
    auto led = Board::GetInstance().GetLed();
    led->OnStateChanged();

    switch (state) {
        case kDeviceStateUnknown:
        case kDeviceStateIdle:
            ESP_LOGI(TAG,"待命");
            // display->SetStatus("待命");
            // display->SetEmotion("neutral");
#ifdef CONFIG_IDF_TARGET_ESP32S3
            // 暂停音频处理器
            // audio_processor_.Stop();
#endif
            break;
        case kDeviceStateConnecting:
            // display->SetStatus("连接中...");
            break;
        case kDeviceStateListening:
            // display->SetStatus("聆听中...");
            // display->SetEmotion("neutral");
            ESP_LOGI(TAG,"聆听中...");
            Board::GetInstance().GetAudioCodec()->EnableInput(true);
#if CONFIG_IDF_TARGET_ESP32S3
            // 开启音频处理器
            // audio_processor_.Start();
#endif
            break;
        case kDeviceStateSpeaking:
            ESP_LOGI(TAG,"说话中...");
            // display->SetStatus("说话中...");
            Board::GetInstance().GetAudioCodec()->EnableOutput(true);
#if CONFIG_IDF_TARGET_ESP32S3
            // 暂停音频处理器
            // audio_processor_.Stop();
#endif
            break;
        default:
            // Do nothing
            break;
    }
}


void Application::StartListening() {
   Schedule([this]() {    
        keep_listening_ = false;
        // 设备空闲
        if (device_state_ == kDeviceStateIdle) {
            if (!socket_protocol_->IsAudioChannelOpened()) {
                SetDeviceState(kDeviceStateConnecting);
                if (!socket_protocol_->OpenAudioChannel()) {
                    SetDeviceState(kDeviceStateIdle);
                    ESP_LOGE(TAG,"Failed to open audio channel, socket con fail!");
                    return;
                }
            }
            SetDeviceState(kDeviceStateListening);
        // 说话中
        } else if (device_state_ == kDeviceStateSpeaking) {
            // 等待扬声器device清空buffer
            vTaskDelay(pdMS_TO_TICKS(120));
            SetDeviceState(kDeviceStateListening);
            // 这里可以设置暂停参数true
        }
    });
}

void Application::StopListening() {
    Schedule([this]() {
        if (device_state_ == kDeviceStateListening) {
            // 提交audio完成通知
            background_task_->Schedule([this]() mutable {
                std::string reqStr = Base64Client::getInstance().ConstructAudioFinishMsgReq();
                ESP_LOGI(TAG,"发送Json：%s",reqStr.c_str());
                // 发送
                socket_protocol_->SendText(reqStr);
            });
            // 更改设备状态为：空闲
            SetDeviceState(kDeviceStateIdle);
        }
    });
}

void Application::Start() {
    /* Setup the board */
    auto& board = Board::GetInstance();
    
    /* Setup the Button callback */
    InitButton();

    /* Setup the display */
   
    /* Setup the audio codec */
    auto codec = board.GetAudioCodec();
    // 音频输入资源就绪：回调设置input标志位
    codec->OnInputReady([this, codec]() {
        BaseType_t higher_priority_task_woken = pdFALSE;
        xEventGroupSetBitsFromISR(event_group_, AUDIO_INPUT_READY_EVENT, &higher_priority_task_woken);
        return higher_priority_task_woken == pdTRUE;
    });
    // 音频输出资源就绪：回调设置output标志位
    codec->OnOutputReady([this]() {
        BaseType_t higher_priority_task_woken = pdFALSE;
        xEventGroupSetBitsFromISR(event_group_, AUDIO_OUTPUT_READY_EVENT, &higher_priority_task_woken);
        return higher_priority_task_woken == pdTRUE;
    });
    codec->Start();
   
    /* Start the main loop */
    xTaskCreate([](void* arg) {
        Application* app = (Application*)arg;
        app->MainLoop();
        vTaskDelete(NULL);
    }, "main_loop", 4096 * 2, this, 2, nullptr);

    /* Wait for the network to be ready */
    printf("开始配网...\n");
    board.StartNetwork();
    printf("配网结束\n");

    /* Wait for the socket connect ready */
    vTaskDelay(pdMS_TO_TICKS(1000));
    printf("开始连接socket Server...\n");
    socket_protocol_->OpenAudioChannel();
    printf("连接socket Server SUCCESS\n");
    
    // 注册Socket接收回调
    socket_protocol_->OnIncomingJson([this](const cJSON* root) {
        // Parse JSON data
        auto type = cJSON_GetObjectItem(root, "event_type");
        ESP_LOGI(TAG,"weosocket获取json类型：%s",type->valuestring);
        if (strcmp(type->valuestring, "conversation.audio.delta") == 0) {
            cJSON* data = cJSON_GetObjectItem(root, "data");
            if (cJSON_IsObject(data)) {
                cJSON* content = cJSON_GetObjectItem(data, "content");
                if (cJSON_IsString(content) && content->valuestring != NULL) {
                    Schedule([this]() {
                        aborted_ = false;
                        if (device_state_ == kDeviceStateIdle || device_state_ == kDeviceStateListening) {
                            SetDeviceState(kDeviceStateSpeaking);
                        }
                    });

                    std::lock_guard<std::mutex> lock(mutex_);
                    ESP_LOGI("INPUT_JSON", "audio-delta: 这是base64后的音频片段");
                    ESP_LOGI("INPUT_JSON","收到base64音频：%s",content->valuestring);

                    // base64解码
                    Base64Client& base64 = Base64Client::getInstance();
                    std::vector<int16_t> pcm = base64.Base64Decode(std::string(content->valuestring));

                    // player
                    if (device_state_ == kDeviceStateSpeaking) {
                        audio_decode_queue_.emplace_back(std::move(pcm));
                    }
                }
            }
        } else if(strcmp(type->valuestring, "conversation.message.delta")) {
            // 流式词汇下发，可在屏幕打印出来，这里ignore
        } else if(strcmp(type->valuestring, "conversation.message.completed")) {
            // 流式词汇整句下发完成
            cJSON* data = cJSON_GetObjectItem(root, "data");
            if (cJSON_IsObject(data)) {
                cJSON* content = cJSON_GetObjectItem(data, "content");
                if (cJSON_IsString(content) && content->valuestring != NULL) {
                    ESP_LOGI("JSON", "message-completed: %s", content->valuestring);
                }
            }
        }
        
    });
}


// 语音循环函数（在input和output资源ready情况下，循环处理音频数据，根据设备状态进行倾听和播放）
void Application::MainLoop() {
    while (true) {
        // 等待事件组中特定事件位被设置
        auto bits = xEventGroupWaitBits(event_group_,
            SCHEDULE_EVENT | AUDIO_INPUT_READY_EVENT | AUDIO_OUTPUT_READY_EVENT,
            pdTRUE,  //事件位被设置并函数返回后，自动清除事件位
            pdFALSE, //任意一个事件位被设置 函数就会返回
            portMAX_DELAY); //任务超时时间，portMAX_DELAY：任务将无限等待

        if (bits & AUDIO_INPUT_READY_EVENT) {
            InputAudio();
        }
        if (bits & AUDIO_OUTPUT_READY_EVENT) {
            OutputAudio();
        }
        if (bits & SCHEDULE_EVENT) {
            mutex_.lock();
            std::list<std::function<void()>> tasks = std::move(main_tasks_);
            mutex_.unlock();
            for (auto& task : tasks) {
                task();
            }
        }
    }
}

void Application::InputAudio() {
    auto codec = Board::GetInstance().GetAudioCodec();
    std::vector<int16_t> data;
    // read audioData
    if (!codec->InputData(data)) {
        return;
    }

    // // 编码处理
    // if (codec->input_sample_rate() != 16000) {
    //     if (codec->input_channels() == 2) {
    //     // 双通道采集处理
    //     } else {
    //     //单通道采集（默认）  
    //     }
    // }
    
// #if CONFIG_IDF_TARGET_ESP32S3
//     // 声学回响处理 和 关键词识别（暂时忽略）
//     // if (audio_processor_.IsRunning()) {
//     //     audio_processor_.Input(data);
//     // }
//     // if (wake_word_detect_.IsDetectionRunning()) {
//     //     wake_word_detect_.Feed(data);
//     // }
// #else
    // 倾听状态才会执行发送
    if (device_state_ == kDeviceStateListening) {
        background_task_->Schedule([this, data = std::move(data)]() mutable {
            // 编码(豆包需以固定格式)
            Base64Client& base64 = Base64Client::getInstance();
            std::string reqStr = base64.ConstructAudioMsgReq(std::move(data));
            ESP_LOGI(TAG,"发送Json：%s",reqStr.c_str());
            // 发送
            socket_protocol_->SendText(reqStr);
        });
    }
// #endif
}

void Application::OutputAudio() {
    auto now = std::chrono::steady_clock::now();
    auto codec = Board::GetInstance().GetAudioCodec();
    // 最大静默时间（s）
    const int max_silence_seconds = 10;

    // 长时间无输出则关闭输出通道
    std::unique_lock<std::mutex> lock(mutex_);
    if (audio_decode_queue_.empty()) {
        // Disable the output if there is no audio data for a long time
        if (device_state_ == kDeviceStateIdle) {
            auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - last_output_time_).count();
            if (duration > max_silence_seconds) {
                codec->EnableOutput(false);
            }
        }
        return;
    }

    // 倾听状态则清空解码队列
    if (device_state_ == kDeviceStateListening) {
        audio_decode_queue_.clear();
        return;
    }

    last_output_time_ = now;
    std::vector<int16_t> data = std::move(audio_decode_queue_.front());
    audio_decode_queue_.pop_front();
    lock.unlock();

    // 后台调度执行（播放pcm音频）
    background_task_->Schedule([this, codec, data = std::move(data)]() mutable {
        if (aborted_) {
            return;
        }
        codec->OutputData(data);
    });
}


void Application::InitButton() {
    // 初始化 和 IO定义
    boot_button_ = new Button();
    boot_button_->SetIo(BOOT_BUTTON_GPIO,false);
    touch_button_ = new Button();
    touch_button_->SetIo(TOUCH_BUTTON_GPIO,false);

    // 回调绑定
    boot_button_->OnClick([this]() {
    if (device_state_ == kDeviceStateStarting) {
        vTaskDelay(pdMS_TO_TICKS(1000));
        // Reboot the device
        esp_restart();
    }
    // ToggleChatState();
    });
    touch_button_->OnPressDown([this]() {
        StartListening();
    });
    touch_button_->OnPressUp([this]() {
        StopListening();
    });
}